package game.games.paint;

import game.GameListener;
import game.Logger;
import game.cellmap.AbstractCellMapGame;
import game.console.AbstractMessageAndIteratorConsoleStream;
import game.console.GameConsole;
import game.console.IConsoleCommand;
import game.console.IConsoleStream;
import game.console.MessageConsoleStream;
import game.games.carcassonne.IterablePoint;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

import javax.swing.SwingUtilities;

public class Paint extends AbstractCellMapGame<PixelMap>
{
    private static Paint instance;
    
    public synchronized static Paint getInstance()
    {
        if (instance == null)
        {
            synchronized (Paint.class)
            {
                instance = new Paint();
                for (IConsoleCommand commandObj : instance.getCommands())
                {
                    GameConsole.getInstance().addConsoleCommand(commandObj);
                }
            }
        }
        return instance;
    }
    
    public Paint()
    {
        super(true, new PixelMap());
        final GameListener gameListener = GameListener.getInstance();
        gameListener.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e)
            {
                if (isRunning())
                {
                    if (SwingUtilities.isRightMouseButton(e))
                    {
                        boolean currentColorFound = false;
                        int i = 0;
                        for (; i < colors.length; i++)
                        {
                            Color color = colors[i];
                            if (currentColorFound)
                            {
                                selectedColor = color;
                                return;
                            }
                            if (color == selectedColor)
                            {
                                currentColorFound = true;
                            }
                        }
                        if (i == colors.length)
                        {
                            selectedColor = colors[0];
                        }
                    }
                    else if (SwingUtilities.isLeftMouseButton(e))
                    {
                        Point mouseCoords = getMousePoint();
                        if (mouseCoords != null)
                        {
                            setPixel(mouseCoords.x, mouseCoords.y, selectedColor);
                        }
                    }
                }
            }
        });
        gameListener.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e)
            {
                if (isRunning())
                {
                    if (SwingUtilities.isLeftMouseButton(e))
                    {
                        Point mouseCoords = getMousePoint();
                        if (mouseCoords != null)
                        {
                            setPixel(mouseCoords.x, mouseCoords.y, selectedColor);
                        }
                    }
                }
            }
        });
    }
    
    // colors
    private final Color[] colors        = new Color[] { Color.BLACK, Color.BLUE, Color.CYAN, Color.DARK_GRAY, Color.GRAY, Color.GREEN, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED, Color.WHITE, Color.YELLOW };
    private Color         selectedColor = Color.BLACK;
    // reset
    private boolean       resetScreen   = true;
    
    @Override
    public BufferedImage getImage()
    {
        Dimension mapSize = getMap().getCellMapSize();
        // image
        BufferedImage image = new BufferedImage(mapSize.width, mapSize.height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D imageGraphics = image.createGraphics();
        for (IterablePoint<Color> i = getMap().getCells().getIterator(); i.hasNext();)
        {
            Point position = i.getCurrentPoint();
            Color color = i.next();
            if (position.equals(getMousePoint()))
            {
                getMap().fillRect(imageGraphics, position, selectedColor);
            }
            else
            {
                if (color != null)
                {
                    getMap().fillRect(imageGraphics, position, color);
                }
            }
            if (getMap().getCellSize() > 2)
            {
                // paint map
                getMap().drawRect(imageGraphics, position, Color.BLACK, 1);
            }
        }
        return image;
    }
    
    @Override
    protected void doNext()
    {
    }
    
    @Override
    protected synchronized void reset()
    {
        getMap().setMapSize(getMap().calcMaxSize(getFrameSize()));
        super.reset();
    }
    
    private List<IConsoleCommand> getCommands()
    {
        List<IConsoleCommand> commands = new ArrayList<IConsoleCommand>();
        commands.add(new IConsoleCommand() {
            @Override
            public String getCommand()
            {
                return "colors";
            }
            
            @Override
            public String[] getSynonym()
            {
                return null;
            }
            
            @Override
            public String getInfo()
            {
                return null;
            }
            
            @Override
            public IConsoleStream fireCommand(String command)
            {
                return new AbstractMessageAndIteratorConsoleStream<Color>() {

                    @Override
                    protected String getMessage()
                    {
                        return colors.length + " Colors available";
                    }

                    @Override
                    protected Color[] getValues()
                    {
                        return colors;
                    }

                    @Override
                    protected String getMessage(Color current)
                    {
                        return getIndex() + " " + current;
                    }
                };
            }
        });
        commands.add(new IConsoleCommand() {
            @Override
            public String getCommand()
            {
                return "color";
            }
            
            @Override
            public String[] getSynonym()
            {
                return null;
            }
            
            @Override
            public String getInfo()
            {
                return null;
            }
            
            @Override
            public IConsoleStream fireCommand(String command)
            {
                String message = "";
                int index = Integer.parseInt(command);
                if (index >= 0 && index < colors.length)
                {
                    selectedColor = colors[index];
                    message = "new color " + index + " = " + selectedColor;
                }
                else
                {
                    message = "unknown color " + index;
                }
                return new MessageConsoleStream(message);
            }
        });
        return commands;
    }
    
    private void setPixel(int x, int y, Color selectedColor2)
    {
        if (x < 0 || x >= getMap().getMapSize().getWidth() || 
            y < 0 || y >= getMap().getMapSize().getHeight())
        {
            Logger.log("WARN: setPixel out of range: x = " + x + "; y = " + y);
        }
        else
        {
            getMap().getCells().setValue(new Point(x, y), selectedColor);
        }
    }
    
    public static void main(String[] args)
    {
        Thread t = new Thread(Paint.getInstance(), "Paint");
        t.start();
    }
}
